package cn.edu.tju.elm.controller;

import cn.edu.tju.core.model.HttpResult;
import cn.edu.tju.core.model.User;
import cn.edu.tju.core.security.service.UserService;
import cn.edu.tju.core.security.repository.UserRepository;
import cn.edu.tju.elm.dto.wallet.WalletOperationDto;
import cn.edu.tju.elm.dto.wallet.WalletDto;
import cn.edu.tju.elm.dto.wallet.WalletRuleDto;
import cn.edu.tju.elm.dto.wallet.WalletTransactionDto;
import cn.edu.tju.elm.service.WalletService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

@RestController
@RequestMapping("/api/wallet")
@Tag(name = "电子钱包管理", description = "提供钱包的充值、提现、转账、查询等接口")
public class WalletController {

    @Autowired
    private UserService userService;

    @Autowired
    private WalletService walletService;

    @Autowired
    private UserRepository userRepository;

    // ========== 钱包管理接口 ==========

    @PostMapping("")
    @Operation(summary = "创建钱包", description = "为用户创建电子钱包")
    public HttpResult<WalletDto> createWallet() {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        // 调用服务层创建钱包
        WalletDto wallet = walletService.createWallet(currentUser.getId(), currentUser);
        
        return HttpResult.success(wallet);
    }

    @GetMapping("")
    @Operation(summary = "获取我的钱包信息", description = "获取当前用户的钱包信息")
    public HttpResult<WalletDto> getMyWallet() {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        // 调用服务层获取钱包信息
        WalletDto wallet = walletService.getWalletByUserId(currentUser.getId());
        
        return HttpResult.success(wallet);
    }

    @GetMapping("/user/{userId}")
    @Operation(summary = "获取用户钱包信息", description = "根据用户ID获取钱包信息")
    public HttpResult<WalletDto> getWalletByUserId(@PathVariable Long userId) {
        // 获取当前登录用户
        userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        // 调用服务层获取钱包信息
        WalletDto wallet = walletService.getWalletByUserId(userId);
        
        return HttpResult.success(wallet);
    }

    @GetMapping("/exists/{userId}")
    @Operation(summary = "检查钱包是否存在", description = "检查指定用户是否已创建钱包")
    public HttpResult<Boolean> checkWalletExists(@PathVariable Long userId) {
        // 获取当前登录用户
        userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        // 调用服务层检查钱包是否存在
        boolean exists = walletService.existsByUserId(userId);
        
        return HttpResult.success(exists);
    }

    @PostMapping("/purchase-svip")
    @Operation(summary = "购买SVIP会员", description = "花费19.99元购买SVIP会员（30天）")
    public HttpResult<WalletDto> purchaseSvip() {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        // 调用服务层购买SVIP
        WalletDto wallet = walletService.purchaseSvip(currentUser.getId(), currentUser.getId());
        
        return HttpResult.success(wallet);
    }

    // ========== 资金操作接口 ==========

    @PostMapping("/recharge")
    @Operation(summary = "充值", description = "为钱包进行充值操作")
    public HttpResult<WalletTransactionDto> recharge(@RequestBody WalletOperationDto operationDto) {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        operationDto.setUserId(currentUser.getId());
        operationDto.setOperator(currentUser.getId());

        // 调用服务层进行充值
        WalletTransactionDto transaction = walletService.recharge(operationDto);
        
        return HttpResult.success(transaction);
    }

    @PostMapping("/withdraw")
    @Operation(summary = "提现", description = "从钱包进行提现操作")
    public HttpResult<WalletTransactionDto> withdraw(@RequestBody WalletOperationDto operationDto) {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        operationDto.setUserId(currentUser.getId());
        operationDto.setOperator(currentUser.getId());

        // 调用服务层进行提现
        WalletTransactionDto transaction = walletService.withdraw(operationDto);
        
        return HttpResult.success(transaction);
    }

    @PostMapping("/pay")
    @Operation(summary = "支付", description = "使用钱包进行支付操作")
    public HttpResult<WalletTransactionDto> pay(@RequestBody WalletOperationDto operationDto) {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        operationDto.setUserId(currentUser.getId());
        operationDto.setOperator(currentUser.getId());

        // 调用服务层进行支付
        WalletTransactionDto transaction = walletService.pay(operationDto);
        
        return HttpResult.success(transaction);
    }

    @PostMapping("/transfer")
    @Operation(summary = "转账", description = "向其他用户进行转账操作")
    public HttpResult<List<WalletTransactionDto>> transfer(@RequestBody WalletOperationDto operationDto) {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        operationDto.setUserId(currentUser.getId());
        operationDto.setOperator(currentUser.getId());

        if (operationDto.getTargetUserId() == null && operationDto.getTargetPhoneNumber() != null) {
            User target = userRepository.findOneByPhoneNumber(operationDto.getTargetPhoneNumber())
                    .orElseThrow(() -> new IllegalArgumentException("收款用户不存在"));
            operationDto.setTargetUserId(target.getId());
        }
        if (operationDto.getTargetUserId() == null) {
            throw new IllegalArgumentException("未指定收款用户");
        }

        // 调用服务层进行转账
        List<WalletTransactionDto> transactions = walletService.transfer(operationDto);
        
        return HttpResult.success(transactions);
    }

    @PostMapping("/refund")
    @Operation(summary = "退款", description = "进行退款操作")
    public HttpResult<WalletTransactionDto> refund(@RequestBody WalletOperationDto operationDto) {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        operationDto.setUserId(currentUser.getId());
        operationDto.setOperator(currentUser.getId());

        // 调用服务层进行退款
        WalletTransactionDto transaction = walletService.refund(operationDto);
        
        return HttpResult.success(transaction);
    }

    @PostMapping("/freeze")
    @Operation(summary = "冻结资金", description = "冻结钱包中的资金")
    public HttpResult<WalletTransactionDto> freeze(@RequestBody WalletOperationDto operationDto) {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        operationDto.setUserId(currentUser.getId());
        operationDto.setOperator(currentUser.getId());

        // 调用服务层冻结资金
        WalletTransactionDto transaction = walletService.freeze(operationDto);
        
        return HttpResult.success(transaction);
    }

    @PostMapping("/unfreeze")
    @Operation(summary = "解冻资金", description = "解冻钱包中被冻结的资金")
    public HttpResult<WalletTransactionDto> unfreeze(@RequestBody WalletOperationDto operationDto) {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        operationDto.setUserId(currentUser.getId());
        operationDto.setOperator(currentUser.getId());

        // 调用服务层解冻资金
        WalletTransactionDto transaction = walletService.unfreeze(operationDto);
        
        return HttpResult.success(transaction);
    }

    // ========== 透支管理接口 ==========

    @PostMapping("/overdraft/set-limit")
    @Operation(summary = "设置透支额度", description = "设置钱包的透支额度（仅管理员）")
    public HttpResult<WalletDto> setOverdraftLimit(@RequestBody WalletOperationDto operationDto) {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        // 权限检查：只有管理员才能修改透支额度
        boolean isAdmin = currentUser.getAuthorities().stream()
                .anyMatch(auth -> "ADMIN".equals(auth.getName()));
        if (!isAdmin) {
            throw new AccessDeniedException("普通用户无法修改透支额度，请联系管理员");
        }

        operationDto.setUserId(currentUser.getId());
        operationDto.setOperator(currentUser.getId());

        // 调用服务层设置透支额度
        WalletDto wallet = walletService.setOverdraftLimit(operationDto);
        
        return HttpResult.success(wallet);
    }

    @PostMapping("/overdraft/increase")
    @Operation(summary = "增加透支额度", description = "增加钱包的透支额度（仅管理员）")
    public HttpResult<WalletDto> increaseOverdraftLimit(@RequestBody WalletOperationDto operationDto) {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        // 权限检查：只有管理员才能修改透支额度
        boolean isAdmin = currentUser.getAuthorities().stream()
                .anyMatch(auth -> "ADMIN".equals(auth.getName()));
        if (!isAdmin) {
            throw new AccessDeniedException("普通用户无法修改透支额度，请联系管理员");
        }

        operationDto.setUserId(currentUser.getId());
        operationDto.setOperator(currentUser.getId());

        // 调用服务层增加透支额度
        WalletDto wallet = walletService.increaseOverdraftLimit(operationDto);
        
        return HttpResult.success(wallet);
    }

    @PostMapping("/overdraft/decrease")
    @Operation(summary = "减少透支额度", description = "减少钱包的透支额度（仅管理员）")
    public HttpResult<WalletDto> decreaseOverdraftLimit(@RequestBody WalletOperationDto operationDto) {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        // 权限检查：只有管理员才能修改透支额度
        boolean isAdmin = currentUser.getAuthorities().stream()
                .anyMatch(auth -> "ADMIN".equals(auth.getName()));
        if (!isAdmin) {
            throw new AccessDeniedException("普通用户无法修改透支额度，请联系管理员");
        }

        operationDto.setUserId(currentUser.getId());
        operationDto.setOperator(currentUser.getId());

        // 调用服务层减少透支额度
        WalletDto wallet = walletService.decreaseOverdraftLimit(operationDto);
        
        return HttpResult.success(wallet);
    }

    // ========== 查询服务接口 ==========

    @GetMapping("/transactions")
    @Operation(summary = "获取交易流水", description = "获取当前用户的交易流水记录")
    public HttpResult<Page<WalletTransactionDto>> getMyTransactions(
            @PageableDefault(size = 20, sort = "createTime,desc") Pageable pageable) {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        // 调用服务层获取交易流水
        Page<WalletTransactionDto> transactions = walletService.getTransactions(currentUser.getId(), pageable);
        
        return HttpResult.success(transactions);
    }

    @GetMapping("/transactions/period")
    @Operation(summary = "获取时间段内的交易流水", description = "获取指定时间段内的交易流水记录")
    public HttpResult<List<WalletTransactionDto>> getTransactionsByPeriod(
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        // 调用服务层获取交易流水
        List<WalletTransactionDto> transactions = walletService.getTransactionsByPeriod(
            currentUser.getId(), startDate, endDate);
        
        return HttpResult.success(transactions);
    }

    @GetMapping("/balance/sufficient")
    @Operation(summary = "检查余额是否足够", description = "检查钱包余额是否足够支付指定金额")
    public HttpResult<Boolean> checkBalanceSufficient(@RequestParam BigDecimal amount) {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        // 调用服务层检查余额
        boolean sufficient = walletService.hasSufficientBalance(currentUser.getId(), amount);
        
        return HttpResult.success(sufficient);
    }

    // ========== 规则管理接口 ==========

    @PostMapping("/rules")
    @Operation(summary = "创建奖励规则", description = "创建钱包奖励规则")
    public HttpResult<WalletRuleDto> createRewardRule(@RequestBody WalletRuleDto ruleDto) {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        // 调用服务层创建规则
        WalletRuleDto rule = walletService.createRewardRule(ruleDto, currentUser.getId());
        
        return HttpResult.success(rule);
    }

    @PutMapping("/rules/{ruleId}/enable")
    @Operation(summary = "启用规则", description = "启用指定的钱包规则")
    public HttpResult<WalletRuleDto> enableRule(@PathVariable Long ruleId) {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        // 调用服务层启用规则
        WalletRuleDto rule = walletService.enableRule(ruleId, currentUser.getId());
        
        return HttpResult.success(rule);
    }

    @PutMapping("/rules/{ruleId}/disable")
    @Operation(summary = "禁用规则", description = "禁用指定的钱包规则")
    public HttpResult<WalletRuleDto> disableRule(@PathVariable Long ruleId) {
        // 获取当前登录用户
        User currentUser = userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        // 调用服务层禁用规则
        WalletRuleDto rule = walletService.disableRule(ruleId, currentUser.getId());
        
        return HttpResult.success(rule);
    }

    @GetMapping("/rules/active")
    @Operation(summary = "获取活跃规则", description = "获取所有活跃的钱包规则")
    public HttpResult<List<WalletRuleDto>> getActiveRules() {
        // 获取当前登录用户
        userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        // 调用服务层获取活跃规则
        List<WalletRuleDto> rules = walletService.getActiveRules();
        
        return HttpResult.success(rules);
    }

    @GetMapping("/rules/applicable-deposit")
    @Operation(summary = "获取适用的充值规则", description = "获取适用于指定金额的充值规则")
    public HttpResult<List<WalletRuleDto>> getApplicableDepositRules(@RequestParam BigDecimal amount) {
        // 获取当前登录用户
        userService.getUserWithAuthorities()
                .orElseThrow(() -> new AccessDeniedException("用户未登录"));

        // 调用服务层获取适用规则
        List<WalletRuleDto> rules = walletService.getApplicableDepositRules(amount);
        
        return HttpResult.success(rules);
    }
}
